﻿using PoliAsis.Domain;
using PoliAsis.Domain.Concrete;
using PoliAsis.Domain.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PoliAsis.Business
{
    public class PoliUtility
    {
        public static PoliUser Login(string person_code, string password)
        {
            PoliUser user = new PoliUser();

            if (String.IsNullOrEmpty(person_code) || String.IsNullOrEmpty(password))
            {
                user.InValidate();
                user.ErrMessage = StatusMessages.REQUIERD_DATA_MISSING;
                return user;
            }

            try
            {
                PoliUserDS uds = new PoliUserDS();
                PoliUser where = new PoliUser();
                where.person_code = person_code;
                where.password = password;
                PoliUser db_user = uds.SelectOne(where);

                if (db_user != null)
                {
                    user = db_user;
                    if (!user.IsTokenValid())
                    {
                        //set new authentication token
                        user.auth_token = Guid.NewGuid().ToString();
                        user.auth_token_date = DateTime.Now;
                        uds.UpdateOne(user);
                    }
                }
                else
                {
                    user.InValidate();
                    user.ErrMessage = StatusMessages.INAVLID_LOGIN;
                }
            }
            catch (Exception ex)
            {
                user.InValidate();
                user.ErrMessage = StatusMessages.RUNTIME_ERROR;
                //TODO: log the error for this token
                user.ErrMessage = ex.Message;
            }


            return user;
        }

        public static List<UserCurrentSchedule> GetUserSchedule(string auth_token)
        {
            UserCurrentSchedule ucs = new UserCurrentSchedule();
            List<UserCurrentSchedule> list = new List<UserCurrentSchedule>();

            ErrorStatus st = Utils.VerifyUser(auth_token);
            if (!st.valid)
            {
                ucs.ErrMessage = st.err_message;
                ucs.Valid = false;
                list.Add(ucs);

                return list;
            }

            ucs.userid = st.userid;
            UserCurrentScheduleDS uds = new UserCurrentScheduleDS();
            list = uds.SelectMany(ucs);
            if (list != null && list.Count > 0)
            {
                var data = from c in list
                           orderby c.day, c.start_time ascending
                           select c;

                if (data != null && data.Count() > 0)
                    return data.ToList<UserCurrentSchedule>();
            }
            return list;

        }

        public static List<CourseInfo> GetUserCourses(string auth_token)
        {
            List<CourseInfo> user_courses_info = new List<CourseInfo>();
            CourseInfo info = new CourseInfo();
            ErrorStatus st = Utils.VerifyUser(auth_token);

            if (!st.valid)
            {
                info.ErrMessage = st.err_message;
                info.Valid = false;
                user_courses_info.Add(info);

                return user_courses_info;
            }

            UserCourses uc = new UserCourses();
            uc.userid = st.userid;
            UserCoursesDS ucds = new UserCoursesDS();
            List<UserCourses> user_courses = ucds.SelectMany(uc);

            CourseInfoDS uids = new CourseInfoDS();
            user_courses_info = uids.SelectAll();

            var data = from ui in user_courses_info
                       join c in user_courses on ui.id equals c.courseid
                       select ui;

            if (data != null && data.Count() > 0)
            {
                return data.ToList<CourseInfo>();
            }

            return user_courses_info;
        }

        public static List<CourseInfo> GetUserNotPassCourses(string auth_token)
        {
            List<CourseInfo> list_info = new List<CourseInfo>();
            CourseInfo cinfo = new CourseInfo();
            ErrorStatus st = Utils.VerifyUser(auth_token);

            if (!st.valid)
            {
                cinfo.ErrMessage = st.err_message;
                cinfo.Valid = false;
                list_info.Add(cinfo);

                return list_info;
            }

            UserCoursesDS uds = new UserCoursesDS();
            UserCourses uc = new UserCourses();
            List<UserCourses> list_not_passed = new List<UserCourses>();
            uc.userid = st.userid;
            uc.status = ConstCourseStatus.SUBSCRIBED;
            list_not_passed = uds.SelectMany(uc);

            if (list_not_passed.Count > 0)
            {
                List<CourseInfo> all_courses = new List<CourseInfo>();
                CourseInfoDS infods = new CourseInfoDS();
                all_courses = infods.SelectAll();
                var data = from c in list_not_passed
                           join ac in all_courses on c.courseid equals ac.id
                           select ac;

                if (data != null && data.Count() > 0)
                {
                    return data.ToList();
                }

            }

            return list_info;
        }

        public static List<CourseExam> GetCourseExamCalls(string auth_token, int courseid)
        {
            List<CourseExam> list = new List<CourseExam>();
            CourseExam cexam = new CourseExam();
            ErrorStatus st = Utils.VerifyUser(auth_token);
            if (!st.valid)
            {
                cexam.ErrMessage = st.err_message;
                cexam.Valid = false;
                list.Add(cexam);
                return list;
            }

            UserRegisteredExamsDS urds = new UserRegisteredExamsDS();
            UserRegisteredExams where_registration = new UserRegisteredExams();
            where_registration.userid = st.userid;
            List<UserRegisteredExams> all_registration = urds.SelectMany(where_registration);

            CourseExamDS cds = new CourseExamDS();
            cexam.courseid = courseid;
            list = cds.SelectMany(cexam);
            if (list.Count > 0)
            {
                var d = from exam in list
                        orderby exam.exam_datetime ascending
                        select exam;

                if (d != null && d.Count() > 0)
                {
                    NomClassroomDS nomds = new NomClassroomDS();
                    List<NomClassroom> all_classroom = nomds.SelectAll();
                    List<CourseExam> exams = d.ToList();
                    UserExamRegNotificationDS not_ds = new UserExamRegNotificationDS();
                    UserExamRegNotification where = new UserExamRegNotification();
                    where.userid = st.userid;
                    List<UserExamRegNotification> all_user_not = not_ds.SelectMany(where);
                    foreach (CourseExam ce in exams)
                    {
                        var data = from ar in all_registration
                                   where ar.course_exam_id == courseid
                                   select ar;
                        if (data != null && data.Count() > 0)
                        {
                            ce.already_registered = true;
                        }
                      
                        var nom_data = all_classroom.Where(x => x.id == ce.classroomid);
                        if (nom_data != null && nom_data.Count() > 0)
                        {
                            ce.classroom_name = nom_data.SingleOrDefault<NomClassroom>().name;
                        }

                        var not_data = all_user_not.Where(x => x.course_exam_id == ce.id);
                        ce.notification_set = (not_data != null && not_data.Count() > 0);

                        ce.stop_reg_date_str = ce.stop_reg_date != null ? ce.stop_reg_date.Value.ToString("dd.MM.yyyy") : "";
                        ce.stop_reg_date_str = ce.strat_reg_date != null ? ce.strat_reg_date.Value.ToString("dd.MM.yyyy") : "";
                        ce.exam_datetime_str = ce.exam_datetime != null ? ce.exam_datetime.Value.ToString("dd.MM.yyyy HH:mm") : "";
                    }

                    return list;
                }
            }


            return list;
        }

        public static List<NomClassroom> SearchClassrom(string auth_token, string classrom_name)
        {
            NomClassroom nc = new NomClassroom();
            List<NomClassroom> list = new List<NomClassroom>();

            ErrorStatus st = Utils.VerifyUser(auth_token);

            if (!st.valid)
            {
                nc.ErrMessage = st.err_message;
                nc.Valid = false;
                list.Add(nc);

                return list;
            }

            nc.name = classrom_name;
            NomClassroomDS ds = new NomClassroomDS();
            int numRecords = 0;
            list = ds.Search(nc, 0, 10, out numRecords);

            return list;
        }

        public static UserProfile GetUserProfile(string auth_token)
        {
            UserProfile info = new UserProfile();
            ErrorStatus st = Utils.VerifyUser(auth_token);
            if (!st.valid)
            {
                info.ErrMessage = st.err_message;
                info.Valid = false;
                return info;
            }

            try
            {
                //load basic info
                PoliUserDS uds = new PoliUserDS();
                PoliUser where = new PoliUser();
                where.id = st.userid;
                PoliUser user = uds.SelectOne(where);
                info.name = user.name;
                info.surname = user.surname;
                info.person_code = user.person_code;
                info.matricola = user.matricola;
                info.email = user.email;

                //load major
                NomMajorDS nds = new NomMajorDS();
                NomMajor major = new NomMajor();
                major.id = user.user_major;
                major = nds.SelectOne(major);
                info.user_major_name = major.name;

                //load school
                NomSchoolDS sds = new NomSchoolDS();
                NomSchool school = new NomSchool();
                school.id = major.schoolid;
                school = sds.SelectOne(school);
                info.user_school_name = school.name;

                //load academic years
                NomAcademicYearDS yds = new NomAcademicYearDS();
                NomAcademicYear start_year = new NomAcademicYear();
                start_year.id = user.start_academic_year;
                start_year = yds.SelectOne(start_year);
                info.start_academic_year = start_year.name;

                if (user.finish_academic_year != null)
                {
                    NomAcademicYear stop_year = new NomAcademicYear();
                    stop_year.id = user.finish_academic_year;
                    stop_year = yds.SelectOne(stop_year);
                    info.finish_academic_year = stop_year.name;
                }

                //load courses
                UserCoursesDS cds = new UserCoursesDS();
                UserCourses where_course = new UserCourses();
                where_course.userid = user.id;
                List<UserCourses> all_user_courses = cds.SelectMany(where_course);
                List<NomAcademicYear> all_academic_year = yds.SelectAll();


                CourseInfoDS ds = new CourseInfoDS();
                List<CourseInfo> all_courses_info = ds.SelectAll();
                var data = from c in all_user_courses
                           join ac in all_courses_info on c.courseid equals ac.id
                           join y in all_academic_year on c.academic_year equals y.id
                           orderby c.academic_year ascending
                           select new CourseExamInfo
                           {
                               academic_year = c.academic_year,
                               academic_year_name = y.name,
                               grade = c.grade,
                               status = ConstCourseStatus.GetName(c.status),
                               course = new CourseInfo
                               {
                                   id = ac.id,
                                   credits = ac.credits,
                                   major_name = ac.major_name,
                                   name = ac.name,
                                   school_name = ac.school_name,
                                   semestar_name = ac.semestar_name
                               }
                           };

                if (data != null && data.Count() > 0)
                {
                    info.user_courses = data.ToList<CourseExamInfo>();
                    //total credits
                    info.total_credits = info.user_courses.Sum(x => x.course.credits);
                }

                //gpa, acquired credits
                var passed = from c in info.user_courses
                             where c.grade >= 18
                             select c;
                if (passed != null && passed.Count() > 0)
                {
                    info.average_grade = passed.ToList<CourseExamInfo>().Average(x => x.grade);
                    info.total_credits_acquired = passed.ToList<CourseExamInfo>().Sum(x => x.course.credits);
                }
            }

            catch (Exception ex)
            {
                info.InValidate();
                info.ErrMessage = StatusMessages.RUNTIME_ERROR;
            }

            return info;
        }

        public static BaseObject PushNotification(string auth_token, int course_exam_id)
        {
            ErrorStatus st = Utils.VerifyUser(auth_token);
            BaseObject o = new BaseObject();

            if (!st.valid)
            {
                o.Valid = false;
                o.ErrMessage = st.err_message;
                return o;
            }

            UserExamRegNotificationDS ds = new UserExamRegNotificationDS();
            UserExamRegNotification e = new UserExamRegNotification();
            e.userid = st.userid;
            e.course_exam_id = course_exam_id;
            UserExamRegNotification present = ds.SelectOne(e);
            if (present == null)
            {
                ds.Insert(e);
            }
            else
            {
                o.ErrMessage = "Notification already set";
                o.Valid = false;
            }


            return o;
        }
        public static List<CourseExam> GetListOfNotification(string auth_token)
        {
            List<CourseExam> list = new List<CourseExam>();
            CourseExam ce = new CourseExam();

            ErrorStatus st = Utils.VerifyUser(auth_token);
            if (!st.valid)
            {
                ce.Valid = false;
                ce.ErrMessage = st.err_message;
                list.Add(ce); ;
                return list;
            }

            UserExamRegNotificationDS dsnot = new UserExamRegNotificationDS();
            CourseExamDS dsc = new CourseExamDS();
            CourseDS cor_ds = new CourseDS();
            List<Course> all_courses = cor_ds.SelectAll();
            UserExamRegNotification where_nt = new UserExamRegNotification();
            where_nt.userid = st.userid;

            List<UserExamRegNotification> not_list = dsnot.SelectMany(where_nt);
            List<CourseExam> all_exams = dsc.SelectAll();

            var data = from not in not_list
                       join ex in all_exams on not.course_exam_id equals ex.id
                       join c in all_courses on ex.courseid equals c.id
                       where ex.stop_reg_date > DateTime.Now
                       select new CourseExam
                       {
                           academic_year = ex.academic_year,
                           course_name = c.name,
                           courseid = c.id,
                           exam_datetime = ex.exam_datetime,
                           stop_reg_date = ex.stop_reg_date,
                           strat_reg_date = ex.strat_reg_date,
                           id = ex.id,
                           exam_datetime_str = ex.exam_datetime_str,
                           stop_reg_date_str = ex.stop_reg_date_str,
                           strat_reg_date_str = ex.strat_reg_date_str,
                           notification_set = true
                       };

            if (data != null && data.Count() > 0)
            {
                return data.ToList<CourseExam>();
            }

            return list;
        }



    }
}
